#pragma once
#include "detail.hpp"
#include "files.hpp"
#include "abstract.hpp"

namespace rpc
{
    class JsonMessage : public BaseMessage
    {
    public:
        using ptr = std::shared_ptr<JsonMessage>;
        virtual std::string serialize() override
        {
            std::string body;
            bool ret = JSON::serialize(_body, body);
            if(!ret)  
                return "";
            return body;
        }
        virtual bool deserialize(const std::string& msg) override
        {
            return JSON::deserialize(msg, _body);
        }
        //virtual bool check() = 0;
    protected:
        Json::Value _body;
    };
    class JsonRequest : public JsonMessage
    {
    public:
        using ptr = std::shared_ptr<JsonRequest>;
    };

    class JsonResponse : public JsonMessage
    {
    public:
        using ptr = std::shared_ptr<JsonResponse>;
        virtual bool check() override
        {
            //大部分相应都有状态码，判断响应状态码和状态是否存在和正确即可
            if(_body[KEY_RCODE].isNull())
            {
                ELOG("响应中没有响应状态码");
                return false;
            }
            if(!_body[KEY_RCODE].isIntegral())
            {
                ELOG("响应状态码类型错误");
                return false;
            }
            return true;
        }
        virtual RCode rcode()
        {
            return (RCode)_body[KEY_RCODE].asInt();
        }
        virtual void setRCode(RCode rcode)
        {
            _body[KEY_RCODE] = (int)rcode;
        }
    };
    class RpcRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<RpcRequest>;
        virtual bool check() override
        {
            //rpc请求中，包括请求方法名称：string，参数字段：class
            if(_body[KEY_METHOD].isNull() || !_body[KEY_METHOD].isString())
            {
                ELOG("RPC请求中没有方法名称或其类型错误");
                return false;
            }
            if(_body[KEY_PARAME].isNull() || !_body[KEY_PARAME].isObject())
            {
                ELOG("RPC请求中没有参数信息或其信息类型错误");
                return false;
            }
            return true;
        }
        std::string method()
        {
            return _body[KEY_METHOD].asString();
        }
        void setMethod(const std::string& method_name)
        {
            _body[KEY_METHOD] = method_name;
        }
        Json::Value params()
        {
            return _body[KEY_PARAME];
        }
        void setParams(const Json::Value& params)
        {
            _body[KEY_PARAME] = params;
        }
    };
    class TopicRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<TopicRequest>;
        virtual bool check() override
        {
            if(_body[KEY_TOPIC_KEY].isNull() || !_body[KEY_TOPIC_KEY].isString())
            {
                ELOG("主题请求中没有主题名称或其类型错误");
                return false;
            }
            if(_body[KEY_OPTYPE].isNull() || !_body[KEY_OPTYPE].isIntegral())
            {
                ELOG("主题请求中没有操作类型或其类型错误");
                return false;
            }
            if(_body[KEY_OPTYPE].asInt() == (int)TopicOptype::TOPIC_PUBLISH &&
            (_body[KEY_TOPIC_MSG].isNull() || !_body[KEY_TOPIC_MSG].isString()))
            {
                ELOG("主题发布请求中没有消息内容类型或其类型错误");
                return false;
            }
            return true;
        }
        std::string topicKey()
        {
            return _body[KEY_TOPIC_KEY].asString();
        }
        void setTopicKey(const std::string& key)
        {
            _body[KEY_TOPIC_KEY] = key; 
        }
        TopicOptype optype()
        {
            return (TopicOptype)_body[KEY_OPTYPE].asInt();
        }
        void setOtype(TopicOptype otype)
        {
            _body[KEY_OPTYPE] = (int)otype;
        }
        std::string topicMsg()
        {
            return _body[KEY_TOPIC_MSG].asString();
        }
        void setTopicMsg(const std::string& key)
        {
            _body[KEY_TOPIC_MSG] = key; 
        }
    };

    typedef std::pair<std::string, int> Address;
    class ServiceRequest : public JsonMessage
    {
    public:
        using ptr = std::shared_ptr<ServiceRequest>;
        virtual bool check() override
        {
            if(_body[KEY_METHOD].isNull() || !_body[KEY_METHOD].isString())
            {
                ELOG("服务请求中没有方法名称或其类型错误");
                return false;
            }
            if(_body[KEY_OPTYPE].isNull() || !_body[KEY_OPTYPE].isIntegral())
            {
                ELOG("服务请求中没有操作类型或其类型错误");
                return false;
            }
            //服务发现没有主机信息
            if(_body[KEY_OPTYPE].asInt() != (int)(ServiceOptype::SERVICE_DISCOVERY) &&
            (_body[KEY_HOST].isNull() || 
            !_body[KEY_HOST].isObject() ||
            _body[KEY_HOST][KEY_HOST_IP].isNull() || 
            !_body[KEY_HOST][KEY_HOST_IP].isString()||
            _body[KEY_HOST][KEY_HOST_PORT].isNull() || 
            !_body[KEY_HOST][KEY_HOST_PORT].isIntegral()))
            {
                ELOG("服务请求中主机地址错误");
                return false;
            }
            return true;
        }
        std::string method()
        {
            return _body[KEY_METHOD].asString();
        }
        void setMethod(const std::string& name)
        {
            _body[KEY_METHOD] = name; 
        }
        ServiceOptype optype()
        {
            return (ServiceOptype)_body[KEY_OPTYPE].asInt();
        }
        void setOptype(ServiceOptype otype)
        {
            _body[KEY_OPTYPE] = (int)otype;
        }
        Address host()
        {
            Address addr;
            addr.first = _body[KEY_HOST][KEY_HOST_IP].asString();
            addr.second = _body[KEY_HOST][KEY_HOST_PORT].asInt();
            return addr;
        }
        void setHost(const Address& host)
        {
            Json::Value val;
            val[KEY_HOST_IP] = host.first;
            val[KEY_HOST_PORT] = host.second;
            _body[KEY_HOST] = val;
        }
    };

    class RPCResponse : public JsonResponse
    {
    public:
        using ptr = std::shared_ptr<RPCResponse>;
        virtual bool check() override
        {
            //大部分相应都有状态码，判断响应状态码和状态是否存在和正确即可
            if(_body[KEY_RCODE].isNull() || 
            !_body[KEY_RCODE].isIntegral())
            {
                ELOG("响应中没有响应状态码， 或状态码类型错误");
                return false;
            }
            // if(_body[KEY_RESULT].isNull() || 
            // !_body[KEY_RESULT].isObject())
            // {
            //     ELOG("响应中没有RPC调用结果, 或结果类型错误");
            //     return false;
            // }
            if(_body[KEY_RESULT].isNull())
            {
                ELOG("响应中没有RPC调用结果, 或结果类型错误");
                return false;
            }
            return true;
        }
        Json::Value result()
        {
            return _body[KEY_RESULT];
        }
        void setResult(const Json::Value& result)
        {
            _body[KEY_RESULT] = result;
        } 
    };

    class TopicResponse : public JsonResponse
    {
    public:
        using ptr = std::shared_ptr<TopicResponse>;
    };

    class ServiceResponse : public JsonResponse
    {
    public:
        using ptr = std::shared_ptr<ServiceResponse>;
        virtual bool check() override
        {
            //大部分相应都有状态码，判断响应状态码和状态是否存在和正确即可
            if(_body[KEY_RCODE].isNull() || 
            !_body[KEY_RCODE].isIntegral())
            {
                ELOG("响应中没有响应状态码， 或状态码类型错误");
                return false;
            }
            if(_body[KEY_OPTYPE].isNull() || 
            !_body[KEY_OPTYPE].isIntegral())
            {
                ELOG("响应中没有操作类型， 或操作类型的类型错误");
                return false;
            }
            if(_body[KEY_OPTYPE].asInt() == (int)(ServiceOptype::SERVICE_DISCOVERY) &&
            (_body[KEY_METHOD].isNull() ||
            !_body[KEY_METHOD].isString() ||
            _body[KEY_HOST].isNull() ||
            !_body[KEY_HOST].isArray()))
            {
                ELOG("服务发现响应中响应信息字段错误");
                return false;
            }
            return true;
        }
        Json::Value result()
        {
            return _body[KEY_RESULT];
        }
        void setResult(const Json::Value& result)
        {
            _body[KEY_RESULT] = result;
        } 
        std::string method()
        {
            return _body[KEY_METHOD].asString();
        }
        void setMethod(const std::string method)
        {
            _body[KEY_METHOD] = method ;
        } 
        ServiceOptype optype()
        {
            return (ServiceOptype)_body[KEY_OPTYPE].asInt();
        }
        void setOtype(ServiceOptype otype)
        {
            _body[KEY_OPTYPE] = (int)otype;
        }
        void setHost(std::vector<Address> addrs)
        {
            for(auto& addr : addrs)
            {
                Json::Value val;
                val[KEY_HOST_IP] = addr.first;
                val[KEY_HOST_PORT] = addr.second;
                _body[KEY_HOST].append(val);
            }
        }
        std::vector<Address> hosts()
        {
            std::vector<Address> addrs;
            int sz = _body[KEY_HOST].size();
            for(int i = 0; i < sz; i++)
            {
                Address addr;
                addr.first = _body[KEY_HOST][i][KEY_HOST_IP].asString();
                addr.second = _body[KEY_HOST][i][KEY_HOST_PORT].asInt();
                addrs.push_back(addr);
            }
            return addrs;
        }

    };

    //创建工厂类，实现消息对象的生产
    class MessageFactory
    {
    public:
        static std::shared_ptr<BaseMessage> create(MType mtype)
        {
            switch(mtype)
            {
                case MType::REQ_RPC : return std::make_shared<RpcRequest>();
                case MType::RSP_RPC : return std::make_shared<RPCResponse>();
                case MType::REQ_SERVICE : return std::make_shared<ServiceRequest>();
                case MType::RSP_SERVICE : return std::make_shared<ServiceResponse>();
                case MType::REQ_TOPIC : return std::make_shared<TopicRequest>();
                case MType::RSP_TOPIC : return std::make_shared<TopicResponse>();
                default : return BaseMessage::ptr();
            }
        }
        template<typename T, typename ...Args>
        static std::shared_ptr<T> create(Args&& ...args)
        {
            return std::make_shared<T>(std::forward<T>(args)...);
        }

    };
}